package com.javaExtendsDemo.demo2;

/**
 * Java 继承详解 | 菜鸟教程
 * https://www.runoob.com/w3cnote/java-extends.html
 * <p>
 * Java内部类的定义、如何创建内部类、内部类的分类、内部类与外部类的关系_java_zhao_miao的博客-CSDN博客
 * https://blog.csdn.net/zhao_miao/article/details/83245816
 * <p>
 * 内部类
 * 将一个类定义在另一个类里面，里面的那个类就称为内部类。内部类的出现，再次打破了Java单继承的局限性。
 * <p>
 * 访问特点：
 * <p>
 * 内部类可以直接访问外部类的成员，包括私有成员。
 * 外部类要访问内部类的成员，必须要建立内部类的对象。
 * 内部类分类及共性：
 * 共性：
 * <p>
 * 内部类仍然是一个独立的类，在编译之后会内部类会被编译成独立的.class文件，但是前面冠以外部类的类名和$符号。
 * 内部类不能用普通的方式访问。内部类是外部类的一个成员，因此内部类可以自由地访问外部类的成员变量，无论是否是private的。
 * 成员内部类
 * <p>
 * 在外部类中有成员变量和成员方法，成员内部类就是把整个一个类作为了外部类的成员；
 * 成员内部类是定义在类中方法外的类；
 * 创建对象的格式为：外部类名.内部类名 对象名 = 外部类对象.内部类对象；
 * 成员内部类之所以可以直接访问外部类的成员，那是因为内部类中都持有一个外部类对象的引用：外部类名.this；
 * 成员内部类可以用的修饰符有final，abstract，public，private，protected，static.
 * <p>
 * 静态内部类
 * <p>
 * 静态内部类就是成员内部类加上静态修饰符static，定义在类中方法外。
 * <p>
 * 在外部类中访问静态内部类有两种场景：
 * <p>
 * 在外部类中访问静态内部类中非静态成员：*外部类名.内部类名 对象名 = 外部类名.内部对象*，需要通过创建对象访问；
 * 在外部类中访问静态内部类中的静态成员：同样可以使用上面的格式进行访问，也可以直接使用外部类名.内部类名.成员。
 * 局部内部类
 * <p>
 * 局部内部类是定义在方法中的类。
 * <p>
 * 方法内部类只能在定义该内部类的方法内实例化，不可以在此方法外对其实例化。
 * 方法内部类对象不能使用该内部类所在方法的非final局部变量。
 * 可以用于方法内部类的修饰符有final，abstract；
 * <p>
 * 静态方法中的方法内部类只能访问外部的静态成员。
 * <p>
 * 匿名内部类
 * <p>
 * 匿名内部类是内部类的简化写法，是建立一个带内容的外部类或者接口的子类匿名对象。
 * 前提：
 * 内部类可以继承或实现一个外部类或者接口。
 * 格式：
 * new 外部类名或者接口名(){重写方法};
 * 通常在方法的形式参数是接口或者抽象类，并且该接口中的方法不超过三个时，可以将匿名内部类作为参数传递。
 * <p>
 * 不同修饰符修饰的内容(和内部类无关)
 * 类	成员变量	成员方法	构造方法
 * private		Y	Y	Y
 * 默认	Y	Y	Y	Y
 * protected		Y	Y	Y
 * public	Y	Y	Y	Y
 * abstract	Y		Y
 * static		Y	Y	Y
 * final	Y	Y	Y
 * 注意，常见规则如下：
 * <p>
 * 以后，所有的类都用public修饰。并且，在一个java文件中，只写一个类。
 * 以后，所有的成员变量用private修饰。
 * 以后，所有的成员方法用public修饰。
 * 如果是抽象类或者接口：public abstract + …
 * 以后，所有的构造方法用public修饰。
 * 如果类是工具类或者单例类：构造用private修饰
 * <p>
 * <p>
 * 四种权限修饰符
 * 本类	同包（无关类或子类）	不同包（子类）	不同包（无关类）
 * private	Y
 * 默认	Y	Y
 * protected	Y	Y	Y
 * public	Y	Y	Y	Y
 * 推荐：
 * <p>
 * 成员变量 private
 * 构造方法 public
 * 成员方法 public
 *
 *  内部类的优缺点
 * 内部类的优点:
 *
 * 内部类与外部类可以方便的访问彼此的私有域（包括私有方法、私有属性）。
 * 内部类是另外一种封装，对外部的其他类隐藏。
 * 内部类可以实现java的单继承局限。
 * 内部类的缺点:
 *
 * 结构复杂
 */

class Outer {
    private String str = "外部类中的字符串";

    //**************************
    //定义一个内部类
    class Inner {
        private String inStr = "内部类中的字符串";

        //定义一个普通方法
        public void print() {
            //调用外部类的str属性
            System.out.println(str);
        }
    }

    //**************************
    //在外部类中定义一个方法，该方法负责产生内部类对象并调用print()方法
    public void fun() {
        //内部类对象
        Inner in = new Inner();
        //内部类对象提供的print
        in.print();
    }
}

public class OuterTest {
    public static void main(String[] args) {
        //创建外部类对象
        Outer out = new Outer();
        //外部类方法
        out.fun();
    }

    //外部类中的字符串
}
